#include <common.h>
#include <stdint.h>

#if defined(MULTIPROGRAM) && !defined(TIME_SHARING)
# define MULTIPROGRAM_YIELD() yield()
#else
# define MULTIPROGRAM_YIELD()
#endif

#define NAME(key) \
    [AM_KEY_##key] = #key,

static const char *keyname[256] __attribute__((used)) = {
    [AM_KEY_NONE] = "NONE",
    AM_KEYS(NAME)
};

size_t serial_write(const void *buf, size_t offset, size_t len) {
    // offset 没有用
    char* str = (char*)buf;
    for (int i = 0; i < len; ++i){
        putch(str[i]);
    }
    return len;
}

size_t events_read(void *buf, size_t offset, size_t len) {
    AM_INPUT_KEYBRD_T kb = io_read(AM_INPUT_KEYBRD);
    if (kb.keycode == AM_KEY_NONE) {
        *(char*)buf = '\0';
        return 0;
    }
    const char* key_type = kb.keydown ? "kd " : "ku ";
    const char* key_name = keyname[kb.keycode];
    int ret = sprintf(buf, "%s %s", key_type, key_name);
    assert(ret <= len);
    return ret;
}

size_t dispinfo_read(void *buf, size_t offset, size_t len) {
    int W = io_read(AM_GPU_CONFIG).width;
    int H = io_read(AM_GPU_CONFIG).height;
    int ret = sprintf(buf, "WIDTH:%d\nHEIGHT:%d", W, H);
    return ret;
}

size_t fb_write(const void *buf, size_t offset, size_t len) {
    // 此处 len 是以字节为单位, 绘图是以像素(4 Byte)为单位, 注意转换, buf 和 len 必须四字节对齐
    assert(!((len & 0b11) || ((uintptr_t)buf & 0b11)));
    // 由于 Native 没有实现 AM_GPU_MEMCPY, 所以这里直接报错
    io_write(AM_GPU_MEMCPY, offset, (void *)buf, len>>2);
    return len;
}

static int sbuf_size;
static Area sbuf;

// 往声卡的流缓冲区中写入解码后的音频数据并播放
size_t sb_write(const void *buf, size_t offset, size_t len) {
    sbuf.start = (void *)buf;
    sbuf.end = sbuf.start + len;
    io_write(AM_AUDIO_PLAY, sbuf);
    return len;
}

// 读出当前声卡设备流缓冲区的空闲字节数
size_t sbctl_read(void *buf, size_t offset, size_t len) {
    int32_t count = io_read(AM_AUDIO_STATUS).count;
    *(int32_t*)buf = sbuf_size - count;
    return len;
}

// 初始化声卡设备
size_t sbctl_write(const void *buf, size_t offset, size_t len) {
    assert(io_read(AM_AUDIO_CONFIG).present);
    // 写入 freq, channels, samples 初始化设备
    int32_t* args = (int32_t*)buf;
    io_write(AM_AUDIO_CTRL, args[0], args[1], args[2]);
    // 读出 sbuf 大小
    sbuf_size = io_read(AM_AUDIO_CONFIG).bufsize;
    return len;
}

void init_device() {
    Log("Initializing devices...");
    ioe_init();
}
